package com.googlecode.moneyManager.model;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Collections;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import org.apache.log4j.Logger;

import com.googlecode.moneyManager.service.Builder;

/**
 * @author Sergiy Doroshenko
 */
@Entity
public class Deposit extends BaseEntity {

    private static org.apache.log4j.Logger log = Logger
            .getLogger(Deposit.class);

    protected long layoutDate;

    private long expiredDate;

    private Percentage percent;

    private int term;

    private Contract contract;

    private Bank bank;

    private Customer customer;

    protected Amount amount;

    private List<Replenish> replenish;

    public Deposit() {
    }

    public Deposit(DepositBuilder b) {
        layoutDate = b.layoutDate;
        expiredDate = b.expiredDate;
        percent = b.percent;
        term = b.term;

        contract = b.contract;
        bank = b.bank;

        customer = b.user;
        amount = b.amount;
    }

    /**
     * calculate profit from layoutdate to toDate
     * 
     * @param toDate
     * @return Amount
     */
    Amount getProfitAmount(final long toDate) {
        long depositPeriod = expiredDate - layoutDate;
        long profitPeriod = toDate - layoutDate;
        BigDecimal profitPercent = percent.getNumberOfPercent().multiply(
                BigDecimal.valueOf(profitPeriod)).divide(
                BigDecimal.valueOf(depositPeriod), new MathContext(100));
        BigDecimal profitAmountSum = amount.getAmount().multiply(profitPercent,
                new MathContext(100));
        Amount prAmount = new Amount(profitAmountSum, amount.getCurrency());
        return prAmount;
    }

    /**
     * calculate profit from layoutdate to toDate +
     * replenishs
     * 
     * @param toDate
     * @return Amount
     */
    public Amount getSumProfitAmount(final long toDate) {
        Amount sumAmount = getProfitAmount(toDate);
        log.debug("depositProfit = " + sumAmount);
        if (getReplenish().size() > 0)
            for (Replenish rep : replenish) {
                sumAmount.addToAmount(rep.getProfitAmount(toDate));
            }
        log.debug("sumProfit = " + sumAmount);
        return sumAmount;
    }

    public long getLayoutDate() {
        return layoutDate;
    }

    public void setLayoutDate(long layoutDate) {
        this.layoutDate = layoutDate;
    }

    public long getExpiredDate() {
        return expiredDate;
    }

    public void setExpiredDate(long expiredDate) {
        this.expiredDate = expiredDate;
    }

    @OneToOne(cascade = CascadeType.ALL)
    public Percentage getPercent() {
        return percent;
    }

    public void setPercent(Percentage percent) {
        this.percent = percent;
    }

    public int getTerm() {
        return term;
    }

    public void setTerm(int term) {
        this.term = term;
    }

    public Contract getContract() {
        return contract;
    }

    public void setContract(Contract contract) {
        this.contract = contract;
    }

    @OneToOne(cascade = CascadeType.ALL)
    public Bank getBank() {
        return bank;
    }

    public void setBank(Bank bank) {
        this.bank = bank;
    }

    @ManyToOne(cascade = CascadeType.ALL)
    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @OneToOne(cascade = CascadeType.ALL)
    public Amount getAmount() {
        return amount;
    }

    public void setAmount(Amount amount) {
        this.amount = amount;
    }
    @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL }, mappedBy = "deposit")
    public List<Replenish> getReplenish() {
        return replenish != null ? replenish : Collections.<Replenish>emptyList();
    }

    public void setReplenish(List<Replenish> replenish) {
        this.replenish = replenish;
    }

    public static class DepositBuilder implements Builder<Deposit> {

        // Required parameters
        private final long layoutDate;

        private final long expiredDate;

        private final Percentage percent;

        private final Bank bank;

        private final Customer user;

        protected final Amount amount;

        // Optional
        private int term;

        private BankAccount bankAccount;

        private Contract contract;

        private Branch branch;

        public DepositBuilder(  long layoutDate, 
                                long expiredDate,
                                Percentage percent, 
                                Bank bank, 
                                Customer user, 
                                Amount amount
                               ) {
            super();
            this.layoutDate = layoutDate;
            this.expiredDate = expiredDate;
            this.percent = percent;
            this.bank = bank;
            this.user = user;
            this.amount = amount;
        }

        public Builder<Deposit> term(int t) {
            term = t;
            return this;
        }

        public Builder<Deposit> bankAccount(BankAccount bA) {
            return this;
        }

        public Builder<Deposit> branch(Branch b) {
            branch = b;
            return this;
        }

        public Deposit build() {

            return null;
        }

    }

}
